package ai.mspbots.poc.controller.v2;

import ai.mspbots.poc.controller.v2.dto.IncrementDTO;
import ai.mspbots.poc.controller.v2.dto.PageVO;
import ai.mspbots.poc.controller.v2.dto.SearchTextDTO;
import ai.mspbots.poc.core.exception.EsException;
import ai.mspbots.poc.db.entity.AbbreviationMap;
import ai.mspbots.poc.db.service.AbbreviationMapService;
import ai.mspbots.poc.es.entity.Document;
import ai.mspbots.poc.help.PocEnv;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@RestController
@RequestMapping("/v2/es/search")
public class SearchControllerV2 {

    private static final Logger logger = LoggerFactory.getLogger(SearchControllerV2.class);

    @Autowired
    RestHighLevelClient client;

    private static final int TEN = 10;
    private static final int NINE = 10;

    private static final String INDEX_NAME = SpringUtil.getBean(PocEnv.class).getIndex();

    // 指定在哪个字段搜索
    private static final String SUGGEST_FIELD = "suggest";

    // 自动完成的命名
    private static final String SUGGEST_NAME = "name-suggest";

    @Autowired
    private AbbreviationMapService abbreviationMapService;

    @GetMapping("/abbreviationMap/list")
    public List<AbbreviationMap> getAbbreviationMapLog(String keyword) {
        return abbreviationMapService.list(Wrappers.lambdaQuery(AbbreviationMap.class)
                // .like(SearchHistoryLog::getKeyword, keyword)
                .orderByAsc(AbbreviationMap::getId)
                .last("limit 100"));
    }
    /**
     * 自动完成
     */
    @RequestMapping("/autoComplete")
    public List<String> autoComplete(String suggestValue) {
        String searchText = abbreviationMapService.getMapped(suggestValue);
        logger.info("searchText = {}", searchText);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // suggestField为指定在哪个字段搜索，suggestValue为输入内容，TEN为10，代表输出显示最大条数
        CompletionSuggestionBuilder suggestionBuilderDistrict =
                new CompletionSuggestionBuilder(SUGGEST_FIELD).prefix(searchText, Fuzziness.AUTO)
                        .size(TEN);
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        suggestBuilder.addSuggestion(SUGGEST_NAME, suggestionBuilderDistrict);
        searchSourceBuilder.suggest(suggestBuilder);
        SearchRequest searchRequest = new SearchRequest(INDEX_NAME);
        // searchRequest.types("");
        searchRequest.source(searchSourceBuilder);
        SearchResponse response = null;
        try {
            response = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new EsException("自动完成搜索失败", e);
        }
        Suggest suggest = response.getSuggest();

        List<String> keywords = null;
        if (suggest != null) {
            keywords = new ArrayList<>();
            List<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> entries =
                    suggest.getSuggestion(SUGGEST_NAME).getEntries();
            for (Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option> entry : entries) {
                for (Suggest.Suggestion.Entry.Option option : entry.getOptions()) {
                    String keyword = option.getText().string();
                    if (StringUtils.hasText(keyword)) {
                        if (keywords.contains(keyword)) {
                            continue;
                        }
                        keywords.add(keyword);
                        if (keywords.size() >= NINE) {
                            break;
                        }
                    }
                }
            }
        }
        return keywords;
    }

    @Autowired
    private SearchConfig searchConfig;

    @PostMapping("/search")
    public PageVO<Document> search(@RequestBody SearchTextDTO searchText) {
        String text = abbreviationMapService.getMapped(searchText.getSearchText());
        if (StrUtil.isEmpty(text)) {
            return null;
        }
        try (INDArray vector = searchConfig.vectorized(text)) {
            float[] floatVector = vector.toFloatVector();
            logger.info("floatVector = {}", floatVector);
            double distance = calculateEuclideanDistance(floatVector);
            logger.info("distance = {}", distance);
            if (distance < 1) {
                return searchConfig.search(text, searchText.getPage(), searchText.getSize());
            }
            return searchConfig.search(text, floatVector, searchText.getPage(), searchText.getSize());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static double calculateEuclideanDistance(float[] vector) {
        double sum = 0.0;
        for (double value : vector) {
            sum += value * value; // 计算每个元素的平方
        }
        return Math.sqrt(sum); // 返回平方根
    }


    @PostMapping("/increment")
    public void increment(@RequestBody IncrementDTO incrementDTO) {
        try {
            searchConfig.updateDocumentWeight(incrementDTO);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
